package com.bridge.client.bridgedynamcclient.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.bridge.client.bridgedynamcclient.bean.ChoiceItem;
import com.bridge.client.bridgedynamcclient.bean.UrlConstant;
import com.bridge.client.bridgedynamcclient.bean.excel.AcceExcelData;
import com.bridge.client.bridgedynamcclient.bean.excel.GPSExcelData;
import com.bridge.client.bridgedynamcclient.bean.excel.MeasureModelCsvData;
import com.bridge.client.bridgedynamcclient.bean.vo.resp.BaseResp;
import com.bridge.client.bridgedynamcclient.bean.vo.resp.BridgeMeasureModelSerialNumData;
import com.bridge.client.bridgedynamcclient.config.exception.BusException;
import com.bridge.client.bridgedynamcclient.utils.*;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.SingleSelectionModel;
import javafx.scene.control.TextField;
import javafx.stage.FileChooser;
import javafx.stage.Window;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class BridgeUploadFileController extends BaseController implements Initializable {


    @FXML
    private TextField tfBridgeName;
    @FXML
    private TextField tfBridgeCode;
    @FXML
    private ChoiceBox<ChoiceItem> cbMeasureType;

    @FXML
    private Button btnChoseFileGPS;
    @FXML
    private TextField tfFileNameGPS;

    @FXML
    private Button btnChoseFileAcce;
    @FXML
    private TextField tfFileNameAcce;

    @FXML
    private Button btnAutoRename;

    @FXML
    private TextField tfFileReName;

    @FXML
    private Button btnUploadFile;

    private File choiceFileGPS;
    private File choiceFileAcce;

    private File lastParentFile;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        initListener();
    }

    private void initListener() {
        initChoiceType(cbMeasureType, DataHelper.getMeasureType());

        tfFileNameGPS.setEditable(false);
        tfFileNameAcce.setEditable(false);

        //选择文件
        btnChoseFileGPS.setOnAction(a -> {
            File file = chooseExcelFile(btnChoseFileGPS.getScene().getWindow());
            if (file != null) {
                tfFileNameGPS.setText(file.getName());
                btnChoseFileGPS.setText("重选GPS文件");
                choiceFileGPS = file;
                lastParentFile=file.getParentFile();
            }
        });
        //选择文件
        btnChoseFileAcce.setOnAction(a -> {
            File file = chooseExcelFile(btnChoseFileAcce.getScene().getWindow());
            if (file != null) {
                tfFileNameAcce.setText(file.getName());
                btnChoseFileAcce.setText("重选加速度文件");
                choiceFileAcce = file;
                lastParentFile=file.getParentFile();
            }
        });

        //自动命名
        btnAutoRename.setOnAction(a -> {

            try {
                String bridgeCode = checkTextFieldParam(tfBridgeCode, "请输入桥梁编码");

                postCheckFileAutoName(bridgeCode, cbMeasureType.getValue().getValue());

            } catch (Exception e) {
                if (e instanceof BusException) {
                    FXMLUtil.showAlertInfo(e.getMessage());
                }
            }
        });

        //上传文件
        btnUploadFile.setOnAction(a -> {
            try {
                String bridgeName = checkTextFieldParam(tfBridgeName, "请输入桥梁名称");
                String bridgeCode = checkTextFieldParam(tfBridgeCode, "请输入桥梁编码");
                if (choiceFileGPS == null) {
                    throw new BusException("请选择GPS样本文件");
                }
                if (choiceFileAcce == null) {
                    throw new BusException("请选择加速度样本文件");
                }
                String measureType = cbMeasureType.getValue().getValue();
                String fileName = checkTextFieldParam(tfFileReName, "请确认上传文件名称");
                //文件转换成 cvs文件----cvs文件进行上传
                Map<String, String> params = new HashMap<>();
                params.put("fileName", fileName);
                params.put("bridgeName", bridgeName);
                params.put("bridgeCode", bridgeCode);
                params.put("sampleType", measureType);

                uploadFile(choiceFileGPS, choiceFileAcce, params);

            }catch (Exception e) {
                if (e instanceof BusException) {
                    FXMLUtil.showAlertInfo(e.getMessage());
                }
                statusEnd();
            }

        });
    }

    private File chooseExcelFile(Window primaryStage) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("选择 测量样本 文件");
        if(lastParentFile!=null){
            fileChooser.setInitialDirectory(lastParentFile);
        }
        // 设置文件类型过滤器
        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(
                "Excel 文件 (*.xls, *.xlsx)", "*.xls", "*.xlsx");
        fileChooser.getExtensionFilters().add(extFilter);

        // 显示文件选择对话框
        return fileChooser.showOpenDialog(primaryStage);
    }


    private void initChoiceType(ChoiceBox<ChoiceItem> choiceBox, ObservableList<ChoiceItem> items) {
        initChoiceType(choiceBox, items, null);
    }

    private void initChoiceType(ChoiceBox<ChoiceItem> choiceBox, ObservableList<ChoiceItem> items, ChoiceBoxListener listener) {

        choiceBox.setItems(items);

        choiceBox.setSelectionModel(new SingleSelectionModel<ChoiceItem>() {
            @Override
            protected ChoiceItem getModelItem(int i) {
                if (i < 0) {
                    return null;
                }
                return items.get(i);
            }

            @Override
            protected int getItemCount() {
                return items.size();
            }
        });
        choiceBox.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                if (null != listener) {
                    listener.onChoice(choiceBox.getValue());
                }
            }
        });
        //默认选第一个
        choiceBox.getSelectionModel().select(0);

    }

    private interface ChoiceBoxListener {
        void onChoice(ChoiceItem item);
    }


    private String checkTextFieldParam(TextField textField, String showDialogInfo) throws BusException {
        return checkTextFieldParam(textField, showDialogInfo, true);
    }

    private String checkTextFieldParam(TextField textField, String showDialogInfo, boolean necessary) throws BusException {
        String value = textField.getText();
        if (StringUtil.isEmpty(value)) {
            if (necessary) {
                throw new BusException(showDialogInfo);
            }
            return null;
        }
        return value;
    }

    private void postCheckFileAutoName(String bridgeCode, String measureType) {
        Map<String, Object> params = new HashMap<>();
        params.put("bridgeCode", bridgeCode);
        params.put("sampleType", Integer.valueOf(measureType));

        btnAutoRename.setDisable(true);
        new Thread(new Runnable() {
            @Override
            public void run() {
                String postedBody = HttpUtil.postBody(UrlConstant.bridgeGetMeasureFileSerialNum, params, null);
                //返回当前的数据结果，更新数据
                BaseResp<BridgeMeasureModelSerialNumData> baseResp = JSON.parseObject(postedBody, new TypeReference<BaseResp<BridgeMeasureModelSerialNumData>>() {
                });
                if (Objects.isNull(baseResp) || !baseResp.isSuccess()) {
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            FXMLUtil.showAlertInfo(baseResp != null ? baseResp.getMessage() : "处理失败，请重试");
                            btnAutoRename.setDisable(false);
                        }
                    });
                    return;
                }
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        String fileName = bridgeCode + "_sample_" + (baseResp.getData().getSerialNum() + 1) + ".csv";
                        if (measureType.equals("1")) {
                            fileName = bridgeCode + "_park_sample_" + (baseResp.getData().getSerialNum() + 1) + ".csv";
                        }
                        tfFileReName.setText(fileName);
                        btnAutoRename.setDisable(false);
                    }
                });
            }
        }).start();
    }

    private void uploadFile(File gpsFile, File acceFile, Map<String, String> params) {
        //开始--禁用相关按钮
        //结束--放开相关按钮
        statusLoading();
        new Thread(new Runnable() {
            @Override
            public void run() {

                //读取 gps文件
                List<GPSExcelData> tempGPSList=new ArrayList<>();
                readGspExcel(tempGPSList,gpsFile);
                logger.info("tempGPSList size:{}",tempGPSList.size());
                if(tempGPSList.isEmpty()){
                    endWithTip("GPS样本文件，没有数据");
                    return;
                }
                logger.info("tempGPSList one:{}",tempGPSList.get(0));
                //读取 acce文件
                List<AcceExcelData> tempAcceList=new ArrayList<>();
                readAcceExcel(tempAcceList,acceFile);
                logger.info("tempAcceList size:{}",tempAcceList.size());
                if(tempAcceList.isEmpty()){
                    endWithTip("加速度样本文件，没有数据");
                    return;
                }
                logger.info("tempAcceList one:{}",tempAcceList.get(0));

                //两个文件，合并成一个 csv文件
                List<MeasureModelCsvData> multiList=new ArrayList<>();
                //默认赋值第一个数据
                lastGPSData=tempGPSList.get(0);
                combineData(tempGPSList,tempAcceList,multiList);

                if(multiList.isEmpty()){
                    endWithTip("合并后的文件，没有数据");
                    return;
                }

                File csvFileTemp;
                try {

                    Path tempFile = Files.createTempFile("temp_"+params.get("bridgeCode")+"_", ".csv"); // 创建一个临时文件
                    logger.info("创建的临时文件:{} ", tempFile.toString());
                    csvFileTemp = tempFile.toFile();
                    EasyExcel.write(csvFileTemp,MeasureModelCsvData.class)
                            .excelType(ExcelTypeEnum.CSV)
                            .charset(StandardCharsets.UTF_8)
                            .sheet("sheet1")
                            .doWrite(multiList);

                } catch (IOException e) {
                    endWithTip("合并文件出现异常，请重试");
                    return;
                }

                //上传文件
                BaseResp resp = HttpUtil.uploadProxy(UrlConstant.bridgeAddMeasureModel, csvFileTemp, params, BaseResp.class);
                if (Objects.isNull(resp) || !resp.isSuccess()) {
                    endWithTip(resp != null ? resp.getMessage() : "上传失败");
                    return;
                }

                endWithTip("上传成功");
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        tfFileReName.setText("");
                    }
                });
            }
        }).start();

    }


    private void endWithTip(String msg){
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                statusEnd();
                FXMLUtil.showAlertInfo(msg);
            }
        });
    }

    private GPSExcelData lastGPSData;
    private void combineData(List<GPSExcelData> tempGPSList, List<AcceExcelData> tempAcceList, List<MeasureModelCsvData> multiList) {
        Map<String, GPSExcelData> gpsMap = tempGPSList.stream().collect(Collectors.toMap(GPSExcelData::getTimeFormat, Function.identity(),(v1,v2)->v2));
        tempAcceList.forEach(acceItem->{
            GPSExcelData gpsExcelData = gpsMap.get(acceItem.getTimeFormat());
            if(gpsExcelData!=null){
                MeasureModelCsvData modelCsvData = new MeasureModelCsvData();
                modelCsvData.setTime(acceItem.getTime());
                modelCsvData.setZ(String.valueOf(acceItem.getData01()));
                modelCsvData.setLatitude(gpsExcelData.getLatitude());
                modelCsvData.setLongitude(gpsExcelData.getLongitude());
                modelCsvData.setX("0");
                modelCsvData.setY("0");
                multiList.add(modelCsvData);
                lastGPSData=gpsExcelData;
            }else if(lastGPSData!=null){
                MeasureModelCsvData modelCsvData = new MeasureModelCsvData();
                modelCsvData.setTime(acceItem.getTime());
                modelCsvData.setZ(String.valueOf(acceItem.getData01()));
                modelCsvData.setLatitude(lastGPSData.getLatitude());
                modelCsvData.setLongitude(lastGPSData.getLongitude());
                modelCsvData.setX("0");
                modelCsvData.setY("0");
                multiList.add(modelCsvData);
            }
        });
    }

    private void readAcceExcel(List<AcceExcelData> tempAcceList, File acceFile) {

        EasyExcel.read(acceFile, AcceExcelData.class, new ReadListener<AcceExcelData>() {
                    @Override
                    public void invoke(AcceExcelData data, AnalysisContext analysisContext) {
                        data.setTimeFormat(DateUtils.formatTime(data.getTime()));
                        tempAcceList.add(data);
                    }
                    @Override
                    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

                    }
                })
                .sheet()
                .headRowNumber(1)
                .doRead();
    }

    private void readGspExcel(List<GPSExcelData> tempGPSList, File gpsFile) {

        EasyExcel.read(gpsFile, GPSExcelData.class, new ReadListener<GPSExcelData>() {
                    @Override
                    public void invoke(GPSExcelData data, AnalysisContext analysisContext) {
                        data.setTimeFormat(DateUtils.formatTime(data.getTime()));
                        tempGPSList.add(data);
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

                    }
                })
                .sheet()
                .headRowNumber(1)
                .doRead();
    }

    private void statusLoading() {
        btnUploadFile.setText("上传中...");
        btnChoseFileAcce.setDisable(true);
        btnChoseFileGPS.setDisable(true);
        btnUploadFile.setDisable(true);
    }

    private void statusEnd() {
        btnUploadFile.setText("上传文件");
        btnChoseFileAcce.setDisable(false);
        btnChoseFileGPS.setDisable(false);
        btnUploadFile.setDisable(false);
    }

}